﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PSIEpics;
using System.Collections;
using JtextEpicsInterface;

/*
 * this class is for the other epics server program to run 
 * on the same machine
 * as epicsServer is not serializeable so you have to put it here
 * no objects is passed via remoting
 * only valves
 */
namespace epics_server_remoting_class
{
    /// <summary>
    /// the Real Epics Part of the JtextEpics Solution(only the server-ioc part)
    /// <para>this use the PSIEpics for dealing with the epics-ca and simple record</para>
    /// <para>and use microsoft-.net-remoting to communicate with JtextEpicsServer and EpicsJacketServer</para>
    /// <para>since PSIEpics only allowd one server instance one one machine becouse it sieze the socket</para>
    /// <para>so there should be only one instance of this running on one machine</para>
    /// <para>and it hold only one PSIEpics.EpicsServer,and that handles all Records on one machine,JEServer and EJServer will play with these record via this Object</para>
    /// <para>so ther can be multiple JE,orEJ server one one machine</para>
    /// <para>!!!!! IF YOU ARE USING JTEXTEPICSSOLUTION TODEVELPOE YOU OWN CONTRONL PROGRAM， THIS PART IS NOT WHAT YOU SHOULD BE INTERESTING IN!!!</para>
    /// <para>!!!ONLY IF YOUR ARE TRING TO MODIFY JTEXTEPICSSOLUTION ,THEN YOU SHOULD GET familiar WITH THIS CLASS!!</para>
    /// 
    /// </summary>
    public class EpicsServer_Remoting:MarshalByRefObject
    {
        //
        /// <summary>
        /// the PSIEpics server
        /// </summary>
        public EpicsServer   myServer;

        /// <summary>
        /// the table to place the record
        /// </summary>
        public Hashtable RecordList;
        

        /// <summary>
        /// <para>the table to place the  arrayrecord ,since ArrayRecord is so different from normal REcord in PSIEpics</para>
        /// <para>so you need to treat them distinctly,but in JtextEpics they are somehow fused and sometime not that different </para>
        /// </summary>
        public Hashtable RecordArrayList;  


        /// <summary>
        /// Initializes a new instance of the <see cref="EpicsServer_Remoting"/> class.
        /// </summary>
        public EpicsServer_Remoting()
            : base()
        {
            myServer = new EpicsServer();
            RecordList = new Hashtable();
            RecordArrayList = new Hashtable();
        }

        #region Record part
        /// <summary>
        /// add a record
        /// normally Records are double
        /// </summary>
        /// <param name="pvName">the pv name of the record</param>
        /// <param name="force">if you'd like to add the record  no matter if there is already one with the same name</param>
        public void  addRecord<T>(string pvName,bool force)
        {
           //add a Record to the Record list
           //if force the remove the existing one then add again,if not throw an exception
            //this is to hold a Record until it's added to the Record list
            EpicsRecord<T> myRecord;  
            EpicsArrayRecord<T> myArray;

            //if already there kill it
            if (force == true  && RecordList.Contains(pvName))
            {
                disposeRecord(pvName);
            }
            myRecord = myServer.GetEpicsRecord<T>(pvName);
            //add to the Record list
            RecordList.Add(pvName, myRecord);   
            //exception here
        }


        /// <summary>
        /// Adds the record.
        /// but also fill the record informations by using a JtextEpicsInterface.Record_prop
        /// <seealso cref="Record_prop"/>
        /// </summary>
        /// <typeparam name="T">Data type ,ususally double or byte or sbyte</typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="force">if you'd like to add the record  no matter if there is already one with the same name</param>
        /// <param name="my_RP">the Record_prop that holds the record information</param>
        public void  addRecord<T>(string pvName, bool force,Record_prop my_RP)
        {
            //EpicsRecord<T> myRecord;   //this is to hold a Record until it's added to the Record list
            //EpicsArrayRecord<T> myArray;

            addRecord<T>(pvName, force);
            if (my_RP != null)
            {
                setRecordProperty<T>(pvName, my_RP);
            }
            
        }

        /// <summary>
        /// Sets the record property.
        /// olny set the PSIEpics Record propteries ,couse other property ios set out side this in EJ or JE server
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="my_RP">the Record_prop that holds the record information.</param>
        public void setRecordProperty<T>(string pvName,Record_prop my_RP)
        {
            ((EpicsRecord<T>)RecordList[pvName]).DESC = my_RP.DESC;
            ((EpicsRecord<T>)RecordList[pvName]).EGU = my_RP.EGU;
            ((EpicsRecord<T>)RecordList[pvName]).HIGH = my_RP.HIGH;
            ((EpicsRecord<T>)RecordList[pvName]).HIHI = my_RP.HIHI;
            ((EpicsRecord<T>)RecordList[pvName]).LOLO = my_RP.LOLO;
            ((EpicsRecord<T>)RecordList[pvName]).LOW = my_RP.LOW;
            ((EpicsRecord<T>)RecordList[pvName]).SCANINTERVAL = my_RP.SCANINTERVAL;
            ((EpicsRecord<T>)RecordList[pvName]).HighDisplayLimit = my_RP.HighDisplayLimit;
            ((EpicsRecord<T>)RecordList[pvName]).HighDisplayLimit = my_RP.LowDisplayLimit;

        }

        /// <summary>
        /// Sets the record with given pvName.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="val">The value.</param>
        public void setRecord<T>(string pvName, T val)
        {
            ((EpicsRecord<T>)RecordList[pvName]).VAL=val;  //find the Record set the value 
        }


        /// <summary>
        /// Gets the record value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <returns></returns>
        public T getRecord<T>(string pvName)
        {
            return ((EpicsRecord<T>)RecordList[pvName]).VAL;   //find the Record get the value
        }



        /// <summary>
        /// Disposes the record.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        public void disposeRecord<T>(string pvName)
        {       //delet a Record from the server
            ((EpicsRecord<T>)RecordList[pvName]).Dispose();
            RecordList.Remove(pvName);
        }



        /// <summary>
        /// Disposes the record.
        /// </summary>
        /// <param name="pvName">Name of the pv.</param>
        public void disposeRecord(string pvName)
        {       //delet a Record from the server
            ((EpicsRecord)RecordList[pvName]).Dispose();
            RecordList.Remove(pvName);
        }

        #endregion

        #region arrayRecord     
        //handeles the array Records
        
        /// <summary>
        /// Adds an arrayRecord.
        /// </summary>
        /// <typeparam name="T">normally sbyte</typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="length">The length or this record.</param>
        /// <param name="force">force to add</param>
        public void addRecordArray<T>(string pvName,int length,bool force)
        {

            EpicsRecord<T> myRecord;   //this is to hold a Record until it's added to the Record list
            EpicsArrayRecord<T> myArray;

            if (force == true && RecordArrayList.Contains(pvName))
            {
                disposeRecordArray<T>(pvName);
            }
            myArray = myServer.GetEpicsArrayRecord<T>(pvName, length);
            RecordArrayList.Add(pvName, myArray);  //add to the Record list
            
            //exception here
        }


        /// <summary>
        /// Adds an arrayRecord.
        /// </summary>
        /// <typeparam name="T">normally sbyte</typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="length">The length or this record.</param>
        /// <param name="force">force to add</param>
        /// <param name="my_RP">Record Property ,normally array has little information with it</param>
        public void addRecordArray<T>(string pvName, int length, bool force,Record_prop my_RP)
        {
            addRecordArray<T>( pvName, length, force);
            setRecordArrayProperty<T>(pvName, my_RP);
        }


        /// <summary>
        /// Sets the record array property.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="my_RP">The property</param>
        public void setRecordArrayProperty<T>(string pvName, Record_prop my_RP)
        {
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).DESC = my_RP.DESC;
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).EGU = my_RP.EGU;
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).HIGH = my_RP.HIGH;
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).HIHI = my_RP.HIHI;
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).LOLO = my_RP.LOLO;
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).LOW = my_RP.LOW;
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).SCANINTERVAL = my_RP.SCANINTERVAL;
        }


        /// <summary>
        /// Gets the array record values.
        /// </summary>
        /// <typeparam name="T">data type</typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <returns>returns a T[] Array</returns>
        public T[] getRecordArray<T>(string pvName)
        {

            //EpicsRecord<T> myRecord;   //this is to hold a Record until it's added to the Record list
            EpicsArrayRecord<T> myArray;
            myArray = (EpicsArrayRecord<T>)RecordArrayList[pvName];
            int i;
            int length = myArray.VAL.Count;
            T[] returnArray = new T[length];
            //convert an EpicsArrayRecord<T> to normal array
            for (i = 0; i < length; i++)
            {
                returnArray[i] = myArray.VAL[i];
            }
            return returnArray;
            //exceptions here
        }


        /// <summary>
        /// Gets the array record values.
        /// you can set a start and end to get a spciefic part of a array
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="start">The start postion of the array.</param>
        /// <param name="end">The end postion.</param>
        /// <returns>value array T[]</returns>
        public T[] getRecordArray<T>(string pvName,int start,int end)
        {

            //EpicsRecord<T> myRecord;   //this is to hold a Record until it's added to the Record list
            EpicsArrayRecord<T> myArray;
            myArray = (EpicsArrayRecord<T>)RecordArrayList[pvName];

            int i;
            int length = end-start+1;
            T[] returnArray = new T[length];
            for (i = 0; i < length; i++)
            {
                returnArray[i] = myArray.VAL[start+i];
            }
            return returnArray;
            //exceptions here
        }


        /// <summary>
        /// Gets the array record values.
        /// you can set end mark ,it get from the start to the first time it meet the end mark
        /// genetic type is used so can not overload 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="ending">The ending mark.</param>
        /// <returns>the value array the ending mark is returned</returns>
        public T[] getRecordArray2<T>(string pvName, T ending)
        {
            //get to the ending mark

            //EpicsRecord<T> myRecord;   //this is to hold a Record until it's added to the Record list
            EpicsArrayRecord<T> myArray;

            
            myArray = (EpicsArrayRecord<T>)RecordArrayList[pvName];
            int i;
            int length = myArray.VAL.Count;
            T[] returnArrary = new T[length];
            for (i = 0; i < length; i++)
            {
                returnArrary[i] = myArray.VAL[i];
                if (returnArrary[i].Equals(ending))
                    break;
            }
            return returnArrary;
            //exceptions here
        }


        /// <summary>
        /// Sets the  arrayrecord values.
        /// you can specify which part of the array is set to which part of the record
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        /// <param name="Val">The value array .</param>
        /// <param name="begin_src">The begining position of the source array.</param>
        /// <param name="begin_des">The begining position of the destiny array--the array record.</param>
        /// <param name="lenth">The lenth of data you want to set.</param>
        public void setRecordArray<T>(string pvName, T [] Val, int begin_src,int begin_des ,int lenth)
        {
            int i = 0;
            for (i = 0; i <lenth ; i++)
            {
                ((EpicsArrayRecord<T>)RecordArrayList[pvName]).VAL[begin_des +i] = Val[begin_src+i];
            }
        }

        /// <summary>
        /// Disposes thearray record .
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pvName">Name of the pv.</param>
        public void disposeRecordArray<T>(string pvName)
        {
            //delet a arrayRecord from the server
            ((EpicsArrayRecord<T>)RecordArrayList[pvName]).Dispose();
            RecordArrayList.Remove(pvName);
        }



        #endregion
    }
}
